﻿#pragma once

#include <functional>
#include <memory>
#include <QMap>
#include <QString>
/*
动态对象工厂。
通过使用类名字符串来生成对应的类对象。也就是动态生成对象。
由于c++没有反射机制，所以需要自己建立一套能够动态生成对象的机制，以便能够通过配置文件中的配置信息，自动生成不同类型的对象。
用法：
（1）所有需要由对象工厂动态生成对象的类，都需要从Object类派生；
（2）在类的声明部分加入：DECLARE_DYNAMIC_CREATE(类名)，在类的实现文件(.cpp）中加入：DYNAMIC_CREATE(类名)
（3）需要在程序的任何一个地方#include 这个类的头文件（通常加在类的实现文件中即可），并且将类的.cpp文件加入到工程中
（4）调用ObjectFactory::CreateObj("类名")来生成类的对象智能指针(shared_ptr)。
原理：
    通过宏定义，在每个需要动态生成对象的类中，建立一个CreateObj静态函数，同时将这个类的类名和CreateObj函数的std:function对象保存到ObjectFactory的Map中。
    当需要创建某个类的对象时，先通过Map获得这个类的CreateObj静态函数，并调用它即可。
    通过宏定义，简化所有操作。
*/

/**
 * @brief 所有需要能够从对象工厂动态生成对象的类，都需要从Object派生。
 */
class Object
{
protected:
    QString name;
public:
    /**
     * @brief 获取本对象的类的名称。
     * @return 类名称的字符串。
     */
    virtual QString GetClassName() const = 0;

    void SetName(const QString& name) { this->name = name; }
    QString GetName() const { return name; }

    /**
     * @brief 各个Object派生类应重载本函数，完成从SettingData.xml中读入相关配置信息，实现初始化。
     * @param xmlPath 本设备在SettingData.xml中的主路径
     * @return 成功返回true，失败返回false.
     */
    virtual bool InitFromSettingData(const QString& path)
    {
        Q_UNUSED(path);
        return true;
    }

};

/**
 * @brief 对象工厂类。
 */
class ObjectFactory;
extern std::shared_ptr<ObjectFactory> objFactoryPtr;

class ObjectFactory
{
public:
    /**
     * @brief 获取ObjectFactory唯一实例。ObjectFactory不能是静态类，也不能直接声明一个全局对象，这是因为
     *        在其他各个模块以及全局变量/对象初始化完成之前，ObjectFactory无法使用。
     *        所以，采用make_shared<>()方法来生成这个实例。
     * @return
     */
    static ObjectFactory& instance()
    {
        if (objFactoryPtr == nullptr)
            objFactoryPtr = std::make_shared<ObjectFactory>();
        return *objFactoryPtr;
    }

    using ObjCreator = std::function<std::shared_ptr<Object>(void)>;   //简化各个类的CreateObj函数的类型定义。
    int RegisterObj(const QString& className, ObjCreator objCreator);     //将类名和CreateObj在map里做映射。

    /**
     * @brief 创建对象
     * @param className 类的名称
     * @return 对象的shared_ptr
     */
    std::shared_ptr<Object> CreateObj(const QString& className);
private:
    QMap<QString, ObjCreator> creatorMap;
};



#define DECLARE_DYNAMIC_CREATE(CLASS_NAME) public:\
    static std::shared_ptr<Object> CreateObj() { return std::make_shared<CLASS_NAME>(); } \
    QString GetClassName() const override { return #CLASS_NAME; }

#define DYNAMIC_CREATE(CLASS_NAME) \
    static int tmp_##CLASS_NAME = ObjectFactory::instance().RegisterObj(#CLASS_NAME, CLASS_NAME::CreateObj);
